﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DDD;
using Xunit;

using Vector3 = DDD.Vector3<float>;


namespace DokiDokiTest {
    public class TestMatrix3x3 {
        [Fact]
        public void Test_New1 () {
            var m = new Matrix3x3 ();

            Assert.Equal (9, m.ComponentCount);
            Assert.Equal (0, m.M00);
            Assert.Equal (0, m.M01);
            Assert.Equal (0, m.M02);
            Assert.Equal (0, m.M10);
            Assert.Equal (0, m.M11);
            Assert.Equal (0, m.M12);
            Assert.Equal (0, m.M20);
            Assert.Equal (0, m.M21);
            Assert.Equal (0, m.M22);
            Assert.Equal (0, m[0]);
            Assert.Equal (0, m[1]);
            Assert.Equal (0, m[2]);
            Assert.Equal (0, m[3]);
            Assert.Equal (0, m[4]);
            Assert.Equal (0, m[5]);
            Assert.Equal (0, m[6]);
            Assert.Equal (0, m[7]);
            Assert.Equal (0, m[8]);
        }

        [Fact]
        public void Test_New2 () {
            var m = new Matrix3x3 (1, 2, 3,
                                  4, 5, 6,
                                  7, 8, 9);

            Assert.Equal (9, m.ComponentCount);
            Assert.Equal (1, m.M00);
            Assert.Equal (2, m.M01);
            Assert.Equal (3, m.M02);
            Assert.Equal (4, m.M10);
            Assert.Equal (5, m.M11);
            Assert.Equal (6, m.M12);
            Assert.Equal (7, m.M20);
            Assert.Equal (8, m.M21);
            Assert.Equal (9, m.M22);
            Assert.Equal (1, m[0]);
            Assert.Equal (2, m[1]);
            Assert.Equal (3, m[2]);
            Assert.Equal (4, m[3]);
            Assert.Equal (5, m[4]);
            Assert.Equal (6, m[5]);
            Assert.Equal (7, m[6]);
            Assert.Equal (8, m[7]);
            Assert.Equal (9, m[8]);
        }

        [Fact]
        public void Test_New3 () {
            var m = new Matrix3x3 (new float[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
            var expect = new float[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

            Assert.Equal (expect, (float[])m);

        }

        [Fact]
        public void Test_Idexer () {
            var m = new Matrix3x3 ();
            m[0] = 1;
            m[1] = 2;
            m[2] = 3;
            m[3] = 4;
            m[4] = 5;
            m[5] = 6;
            m[6] = 7;
            m[7] = 8;
            m[8] = 9;
            Assert.Equal (1, m[0]);
            Assert.Equal (2, m[1]);
            Assert.Equal (3, m[2]);
            Assert.Equal (4, m[3]);
            Assert.Equal (5, m[4]);
            Assert.Equal (6, m[5]);
            Assert.Equal (7, m[6]);
            Assert.Equal (8, m[7]);
            Assert.Equal (9, m[8]);
        }

        [Fact]
        public void Test_Ideneity () {
            var m = Matrix3x3.Identity ();
            var expect = new float[]{1,0,0,
                                     0,1,0,
                                     0,0,1};
            Assert.Equal (expect, (float[])m);
        }

        [Fact]
        public void Test_Determinant () {
            var m = new Matrix3x3 (1, 2, 3,
                                  1, 0, -1,
                                  2, 1, 1);
            Assert.Equal (-2, m.Determinant);
        }

        [Fact]
        public void Test_Transpose () {
            var m = new Matrix3x3 (1, 2, 3,
                                   4, 5, 6,
                                   7, 8, 9);
            var expected = new float[]{1,4,7,
                                     2,5,8,
                                     3,6,9};

            Assert.Equal (expected, (float[])m.Transpose ());
        }

        [Fact]
        public void Test_Inverse () {
            var m = new Matrix3x3 (1, 0, 1,
                                   2, 1, 1,
                                   0, -1, 2);
            var expected = new float[]{3,-1,-1,
                                       -4,2,1,
                                       -2,1,1};

            Assert.Equal (expected, (float[])m.Inverse ());
        }

        [Fact]
        public void Test_Operator () {
            var m = new Matrix3x3 (1, 0, 1,
                                   2, 1, 1,
                                   0, -1, 2);
            var v = new Vector3 (1, 2, 3);
            var expected = new Vector3 (4, 7, 4);

            Assert.Equal (expected, m * v);
        }

        [Fact]
        public void Test_Equals () {
            var m1 = new Matrix3x3 (0, 1, 2,
                                    3, 4, 5,
                                    6, 7, 8.0f);
            var m2 = new Matrix3x3 (0, 1, 2,
                                    3, 4, 5,
                                    6, 7, 8.02f);
            var tmp = GlobalSettings.Tolerance;

            GlobalSettings.Tolerance = 0.1f;

            Assert.True (m1 == m2);
            Assert.True (m1.Equals (m2));
            Assert.True (m1.Equals ((object)m2));
            Assert.False (m1 != m2);

            GlobalSettings.Tolerance = 0.01f;

            Assert.False (m1 == m2);
            Assert.False (m1.Equals (m2));
            Assert.False (m1.Equals ((object)m2));
            Assert.True (m1 != m2);

            GlobalSettings.Tolerance = tmp;
        }
    }
}
